﻿using System;
using System.Drawing;

namespace Heyo.Class.Helper
{
    public static class ColorHelper
    {
        /// <summary>
        /// 将System.Drawing.Color转化为System.Windows.Media.Color
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        public static System.Windows.Media.Color ToMedia(this System.Drawing.Color c)
        {
            return System.Windows.Media.Color.FromArgb(c.A, c.R, c.G, c.B);
        }
        /// <summary>
        /// 将System.Windows.Media.Color转化为System.Drawing.Color
        /// </summary>
        /// <param name="c"></param>
        /// <returns></returns>
        public static Color ToDrawing(this System.Windows.Media.Color c)
        {
            return Color.FromArgb(c.A, c.R, c.G, c.B);
        }
        public static ColorHsv ToHsv(this System.Windows.Media.Color rgb)
        {
            float min, max, tmp, h, s, v;
            float r = rgb.R * 1.0f / 255, g = rgb.G * 1.0f / 255, b = rgb.B * 1.0f / 255;
            tmp = Math.Min(r, g);
            min = Math.Min(tmp, b);
            tmp = Math.Max(r, g);
            max = Math.Max(tmp, b);
            // H  
            h = 0;
            if (max == min)
            {
                h = 0;
            }
            else if (max == r && g > b)
            {
                h = 60 * (g - b) * 1.0f / (max - min) + 0;
            }
            else if (max == r && g < b)
            {
                h = 60 * (g - b) * 1.0f / (max - min) + 360;
            }
            else if (max == g)
            {
                h = h = 60 * (b - r) * 1.0f / (max - min) + 120;
            }
            else if (max == b)
            {
                h = h = 60 * (r - g) * 1.0f / (max - min) + 240;
            }
            // S  
            if (max == 0)
            {
                s = 0;
            }
            else
            {
                s = (max - min) * 1.0f / max;
            }
            // V  
            v = max;
            return new ColorHsv((int)h, (int)(s * 255), (int)(v * 255));
        }
        public static ColorHsv ToHsv(this System.Drawing.Color rgb)
        {
            return rgb.ToMedia().ToHsv();
        }
        public static Color ToRgb(this ColorHsv hsv)
        {
            if (hsv.H == 360) hsv.H = 359; // 360为全黑，原因不明  
            float r = 0f, g = 0f, b = 0f;
            if (hsv.S == 0)
            {
                return Color.FromArgb(hsv.A, hsv.V, hsv.V, hsv.V);
            }
            float s = hsv.S * 1.0f / 255, v = hsv.V * 1.0f / 255;
            int h1 = (int)(hsv.H * 1.0f / 60), h = hsv.H;
            float f = h * 1.0f / 60 - h1;
            float p = v * (1.0f - s);
            float q = v * (1.0f - f * s);
            float T = v * (1.0f - (1.0f - f) * s);
            switch (h1)
            {
                case 0: r = v; g = T; b = p; break;
                case 1: r = q; g = v; b = p; break;
                case 2: r = p; g = v; b = T; break;
                case 3: r = p; g = q; b = v; break;
                case 4: r = T; g = p; b = v; break;
                case 5: r = v; g = p; b = q; break;
            }
            r = r * 255;
            g = g * 255;
            b = b * 255;
            while (r > 255) r -= 255;
            while (r < 0) r += 255;
            while (g > 255) g -= 255;
            while (g < 0) g += 255;
            while (b > 255) b -= 255;
            while (b < 0) b += 255;
            return Color.FromArgb(hsv.A, (int)r, (int)g, (int)b);
        }
        /// <summary>
        /// 将含有透明度、色调、饱和度、亮度的一组颜色数据转化为System.Drawing.Color
        /// </summary>
        /// <param name="alpha">透明度</param>
        /// <param name="hue">色调</param>
        /// <param name="saturation">饱和度</param>
        /// <param name="brightness">亮度</param>
        /// <returns></returns>
        public static Color FromAhsv(int alpha, float hue, float saturation, float brightness)
        {
            if (0 > alpha
                || 255 < alpha)
            {
                throw new ArgumentOutOfRangeException(
                    "alpha",
                    alpha,
                    "Value must be within a range of 0 - 255.");
            }

            if (0f > hue
                || 360f < hue)
            {
                throw new ArgumentOutOfRangeException(
                    "hue",
                    hue,
                    "Value must be within a range of 0 - 360.");
            }

            if (0f > saturation
                || 1f < saturation)
            {
                throw new ArgumentOutOfRangeException(
                    "saturation",
                    saturation,
                    "Value must be within a range of 0 - 1.");
            }

            if (0f > brightness
                || 1f < brightness)
            {
                throw new ArgumentOutOfRangeException(
                    "brightness",
                    brightness,
                    "Value must be within a range of 0 - 1.");
            }

            if (0 == saturation)
            {
                return Color.FromArgb(
                                    alpha,
                                    Convert.ToInt32(brightness * 255),
                                    Convert.ToInt32(brightness * 255),
                                    Convert.ToInt32(brightness * 255));
            }

            float fMax, fMid, fMin;
            int iSextant, iMax, iMid, iMin;

            if (0.5 < brightness)
            {
                fMax = brightness - (brightness * saturation) + saturation;
                fMin = brightness + (brightness * saturation) - saturation;
            }
            else
            {
                fMax = brightness + (brightness * saturation);
                fMin = brightness - (brightness * saturation);
            }

            iSextant = (int)Math.Floor(hue / 60f);
            if (300f <= hue)
            {
                hue -= 360f;
            }

            hue /= 60f;
            hue -= 2f * (float)Math.Floor(((iSextant + 1f) % 6f) / 2f);
            if (0 == iSextant % 2)
            {
                fMid = (hue * (fMax - fMin)) + fMin;
            }
            else
            {
                fMid = fMin - (hue * (fMax - fMin));
            }

            iMax = Convert.ToInt32(fMax * 255);
            iMid = Convert.ToInt32(fMid * 255);
            iMin = Convert.ToInt32(fMin * 255);

            switch (iSextant)
            {
                case 1:
                    return Color.FromArgb(alpha, iMid, iMax, iMin);
                case 2:
                    return Color.FromArgb(alpha, iMin, iMax, iMid);
                case 3:
                    return Color.FromArgb(alpha, iMin, iMid, iMax);
                case 4:
                    return Color.FromArgb(alpha, iMid, iMin, iMax);
                case 5:
                    return Color.FromArgb(alpha, iMax, iMin, iMid);
                default:
                    return Color.FromArgb(alpha, iMax, iMid, iMin);
            }
        }
    }
}
